package com.vegetable.common.aspect;

import cn.hutool.core.util.ObjectUtil;
import com.vegetable.common.annotation.StockAlertCheck;
import com.vegetable.modules.entity.stock.Stock;
import com.vegetable.modules.entity.stock.po.StockUpdatePO;
import com.vegetable.modules.service.stock.IStockAlertService;
import com.vegetable.modules.service.stock.IStockService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 库存预警检查切面
 * <p>
 * 在库存更新操作完成后自动触发预警检查
 * </p>
 *
 * @author wangruijie
 * @since 2024-09-09
 */
@Slf4j
@Aspect
@Component
@Order(2) // 设置切面优先级，数值越小优先级越高
public class StockAlertAspect {

    @Lazy
    @Resource
    private IStockAlertService stockAlertService;

    @Lazy
    @Resource
    private IStockService stockService;

    /**
     * 定义切入点：使用@StockAlertCheck注解的方法
     */
    @Pointcut("@annotation(com.vegetable.common.annotation.StockAlertCheck)")
    public void stockAlertCheckPointcut() {}

    /**
     * 在标记了@StockAlertCheck注解的方法执行完成后进行预警检查
     */
    @AfterReturning(pointcut = "stockAlertCheckPointcut()", returning = "result")
    public void afterStockOperation(JoinPoint joinPoint, Object result) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            StockAlertCheck annotation = method.getAnnotation(StockAlertCheck.class);
            
            // 检查注解是否启用
            if (annotation == null || !annotation.enabled()) {
                return;
            }
            
            String methodName = method.getName();
            Object[] args = joinPoint.getArgs();
            
            log.debug("执行库存预警检查切面，方法：{}，描述：{}", methodName, annotation.value());
            
            // 根据不同的方法进行相应的预警检查
            if ("updateStock".equals(methodName)) {
                handleUpdateStockAlert(args);
            } else if ("inStock".equals(methodName)) {
                handleInStockAlert(args);
            } else if ("saveOutStock".equals(methodName)) {
                handleOutStockAlert(args);
            } else {
                log.debug("未识别的库存操作方法：{}", methodName);
            }
            
        } catch (Exception e) {
            log.error("库存预警检查切面执行失败", e);
        }
    }

    /**
     * 处理库存更新的预警检查
     */
    private void handleUpdateStockAlert(Object[] args) {
        try {
            if (args != null && args.length > 0 && args[0] instanceof StockUpdatePO) {
                StockUpdatePO updatePO = (StockUpdatePO) args[0];
                
                // 获取更新后的库存信息
                Stock stock = stockService.selectById(updatePO.getId());
                if (ObjectUtil.isNotNull(stock)) {
                    // 按商品+规格维度统计总库存数量
                    List<Stock> stocks = stockService.selectGoodsStock(stock.getCommodityId(), stock.getSpecsId());
                    int totalQuantity = stocks.stream().mapToInt(Stock::getNumber).sum();
                    
                    // 执行预警检查
                    checkStockAlert(stock.getCommodityId(), stock.getSpecsId(), 
                                  totalQuantity, stock.getCommodityName());
                }
            }
        } catch (Exception e) {
            log.error("处理库存更新预警检查失败", e);
        }
    }
    
    /**
     * 处理库存入库的预警检查
     */
    private void handleInStockAlert(Object[] args) {
        try {
            if (args != null && args.length >= 6) {
                // inStock方法参数: orderTime, cost, product, specsId, specsName, inNumber, inWeight, storageType, warehouseId, warehouseName, agentName, packageCost, storageOrderNo, orderId, detailId
                Object productObj = args[2]; // Products product
                Object specsIdObj = args[3]; // Long specsId
                
                if (productObj != null) {
                    // 使用反射获取Products对象的属性
                    Long commodityId = (Long) productObj.getClass().getMethod("getId").invoke(productObj);
                    String commodityName = (String) productObj.getClass().getMethod("getCommonName").invoke(productObj);
                    Long specsId = (Long) specsIdObj;
                    
                    // 按商品+规格维度统计总库存数量
                    List<Stock> stocks = stockService.selectGoodsStock(commodityId, specsId);
                    int totalQuantity = stocks.stream().mapToInt(Stock::getNumber).sum();
                    
                    // 执行预警检查
                    checkStockAlert(commodityId, specsId, totalQuantity, commodityName);
                }
            }
        } catch (Exception e) {
            log.error("处理库存入库预警检查失败", e);
        }
    }
    
    /**
     * 处理库存出库的预警检查
     */
    private void handleOutStockAlert(Object[] args) {
        try {
            if (args != null && args.length >= 4) {
                // saveOutStock方法参数: price_unit, outNumber, outWeight, stockId
                Long stockId = (Long) args[3];
                
                // 获取出库后的库存信息
                Stock stock = stockService.selectById(stockId);
                if (ObjectUtil.isNotNull(stock)) {
                    // 按商品+规格维度统计总库存数量
                    List<Stock> stocks = stockService.selectGoodsStock(stock.getCommodityId(), stock.getSpecsId());
                    int totalQuantity = stocks.stream().mapToInt(Stock::getNumber).sum();
                    
                    // 执行预警检查
                    checkStockAlert(stock.getCommodityId(), stock.getSpecsId(), 
                                  totalQuantity, stock.getCommodityName());
                }
            }
        } catch (Exception e) {
            log.error("处理库存出库预警检查失败", e);
        }
    }
    
    /**
     * 执行库存预警检查
     *
     * @param commodityId 商品ID
     * @param specsId 规格ID
     * @param totalQuantity 按商品+规格维度统计的总库存数量
     * @param commodityName 商品名称
     */
    private void checkStockAlert(Long commodityId, Long specsId, Integer totalQuantity, String commodityName) {
        try {
            boolean needAlert = stockAlertService.checkStockAlert(commodityId, specsId, totalQuantity);
            if (needAlert) {
                log.info("库存预警触发 - 商品：{}，规格ID：{}，总库存数量：{}，已记录预警", commodityName, specsId, totalQuantity);
            } else {
                log.debug("库存正常 - 商品：{}，规格ID：{}，总库存数量：{}", commodityName, specsId, totalQuantity);
            }
        } catch (Exception e) {
            log.error("执行库存预警检查时发生错误，商品ID：{}，规格ID：{}，总库存数量：{}", commodityId, specsId, totalQuantity, e);
        }
    }
}